/**
 * 
 */
package qy.jalgotrade.optimizer.base;

import java.io.Serializable;
import java.time.Duration;

/**
 * The results of the strategy executions.
 * 
 * @author c-geo
 *
 */
public class Results implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2569900131482524499L;

	public enum KPI {
		// @formatter:off
		RESULT, // 总资产:
		RETURN, // 收益率
		SHARPE, // 夏普率
		MAX_DRAWDOWN, // 最大回撤
		LONGEST_DRAWDOWN_DURATION, // 最长回撤期
		TOTAL_TRADES, // 总交易次数
		WIN_RATE, // 胜率
		TOTAL_COMMISSION // 总手续费
		// @formatter:on
	}

	private Parameters __parameters;

	/**
	 * 总资产
	 */
	private double __result;

	/**
	 * 收益率 (累计)
	 */
	private double __return;

	/**
	 * 夏普率
	 */
	private double __sharpe;

	/**
	 * 最大回撤
	 */
	private double __maxDrawDown;

	/**
	 * 最长回撤期
	 */
	private Duration __longestDdDuration;

	/**
	 * 总交易天数
	 */
	private int __totalTradeDays;

	/**
	 * 总交易次数
	 */
	private int __totalTrades;

	/**
	 * 盈利交易次数
	 */
	private int __winTrades;

	/**
	 * 亏损交易次数
	 */
	private int __lossTrades;

	/**
	 * 白忙活交易次数
	 */
	private int __drawTrades;

	/**
	 * 胜率
	 */
	private double __winRate;

	/**
	 * 总交易手续费
	 */
	private double __totalCommission;

	/**
	 * 
	 * @param parameters
	 * @param result
	 */
	public Results(Parameters parameters, double result) {

		this(parameters, result, Double.NaN, Double.NaN, Double.NaN, null, -1, -1, -1, -1, -1, Double.NaN, Double.NaN);
	}

	/**
	 * 
	 * @param parameters
	 * @param result
	 * @param sharpe
	 * @param maxDrawDown
	 * @param totalTrades
	 * @param winRate
	 */
	public Results(Parameters parameters, double result, double returns, double sharpe, double maxDrawDown,
	        Duration longestDdDuration, int totalTradeDays, int totalTrades, int winTrades, int lossTrades,
	        int drawTrades, double winRate, double totalCommission) {

		__parameters = parameters;
		__result = result;
		__return = returns;
		__sharpe = sharpe;
		__maxDrawDown = maxDrawDown;
		__longestDdDuration = longestDdDuration;
		__totalTradeDays = totalTradeDays;
		__totalTrades = totalTrades;
		__winTrades = winTrades;
		__lossTrades = lossTrades;
		__drawTrades = drawTrades;
		__winRate = winRate;
		__totalCommission = totalCommission;
	}

	/**
	 * Returns a sequence of parameter values.
	 * 
	 * @return
	 */
	public Parameters getParameters() {

		return __parameters;
	}

	/**
	 * 
	 * @param kpi
	 * @return
	 */
	public double getBy(KPI kpi) {

		switch (kpi) {
			case RESULT: // 总资产:
				return getResult();
			case RETURN: // 收益率:
				return getReturn();
			case SHARPE: // 夏普率:
				return getSharpe();
			case MAX_DRAWDOWN: // 最大回撤:
				return getMaxDrawDown();
			case WIN_RATE: // 胜率:
				return getWinRate();
			case LONGEST_DRAWDOWN_DURATION: // 最长回撤期, 总交易次数, 总手续费:
			case TOTAL_TRADES:
			case TOTAL_COMMISSION:
				throw new IllegalArgumentException("Unsupported KPI: " + kpi);
			default:
				throw new IllegalArgumentException("Unknown KPI: " + kpi);
		}
	}

	/**
	 * Returns the result (total asset) for a given set of parameters.
	 * 
	 * @return
	 */
	public double getResult() {

		return __result;
	}

	public double getReturn() {

		return __return;
	}

	public double getSharpe() {

		return __sharpe;
	}

	public double getMaxDrawDown() {

		return __maxDrawDown;
	}

	public Duration getLongestDdDuration() {

		return __longestDdDuration;
	}

	public int getTotalTradeDays() {

		return __totalTradeDays;
	}

	public int getTotalTrades() {

		return __totalTrades;
	}

	/**
	 * @return the __winTrades
	 */
	public int getWinTrades() {

		return __winTrades;
	}

	/**
	 * @return the __lossTrades
	 */
	public int getLossTrades() {

		return __lossTrades;
	}

	/**
	 * @return the __drawTrades
	 */
	public int getDrawTrades() {

		return __drawTrades;
	}

	public double getWinRate() {

		return __winRate;
	}

	public double getTotalCommission() {

		return __totalCommission;
	}

	@Override
	public String toString() {

		// @formatter:off
		try {
			return String.format(
			        "Results {result: %.2f,\n    "
			        + "return: %.2f%%,\n    "
			        + "sharpe: %.2f,\n    "
			        + "maxDrawDown: %.2f%%,\n    "
			        + "longestDdDuration: %.2f(hours),\n    "
			        + "totalTradeDays: %d,\n    "
			        + "totalTrades: %d,\n    "
			        + "winTrades: %d,\n    "
			        + "lossTrades: %d,\n    "
			        + "drawTrades: %d,\n    "
			        + "winRate: %.2f%%,\n    "
			        + "totalCommision: %.2f}",
			        // adjusted fields:
			        __result,
			        __return * 100.0,
			        __sharpe,
			        __maxDrawDown * 100.0,
			        __longestDdDuration.getSeconds() / 60.0 / 60.0,
			        __totalTradeDays,
			        __totalTrades,
			        __winTrades,
			        __lossTrades,
			        __drawTrades,
			        __winRate * 100.0,
			        __totalCommission);
		} catch (Exception e) {
			return String.format(
			        "Results {result: %s,\n    "
			        + "return: %s,\n    "
			        + "sharpe: %s,\n    "
			        + "maxDrawDown: %s,\n    "
			        + "longestDdDuration: %s,\n    "
			        + "totalTradeDays: %d,\n    "
			        + "totalTrades: %s,\n    "
			        + "winTrades: %d,\n    "
			        + "lossTrades: %d,\n    "
			        + "drawTrades: %d,\n    "
			        + "winRate: %s,\n    "
			        + "totalCommision: %s}",
			        // ori fields:
			        __result,
			        __return,
			        __sharpe,
			        __maxDrawDown,
			        __longestDdDuration,
			        __totalTradeDays,
			        __totalTrades,
			        __winTrades,
			        __lossTrades,
			        __drawTrades,
			        __winRate,
			        __totalCommission);
		}
		// @formatter:on
	}
}
